﻿' Copyright © Microsoft Corporation.  All Rights Reserved.
' This code released under the terms of the 
' Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
' <copyright file="SensitiveSlider.vb" company="Microsoft">
'     Copyright © Microsoft Corporation. All rights reserved.
' </copyright>
' <summary>Implements the SensitiveSlider class</summary>
' <author>Microsoft Expression Encoder Team</author>

Imports Microsoft.VisualBasic
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Controls.Primitives
Imports System.Windows.Input

Namespace ExpressionMediaPlayer
	''' <summary>
	''' A timeline slider control class.
	''' </summary>
    <TemplatePart(Name:="HorizontalThumb", Type:=GetType(Thumb)), TemplatePart(Name:="VerticalThumb", Type:=GetType(Thumb))> _
    Public Class SensitiveSlider
        Inherits Slider
        ''' <summary>
        ''' part names used for the up/down track parts in slider
        ''' </summary>
        Private Shared ReadOnly PartNamesArray() As String = {"LeftTrack", "RightTrack", "UpTrack", "DownTrack", "HorizontalTrackLargeChangeDecreaseRepeatButton", "HorizontalTrackLargeChangeIncreaseRepeatButton", "VerticalTrackLargeChangeDecreaseRepeatButton", "VerticalTrackLargeChangeIncreaseRepeatButton"}
        ' old part names in Slider control
        ' new part names in Slider control
        ''' <summary>
        ''' Property string for HorizontalThumb. (old)
        ''' </summary>
        Private Const HorizontalThumb As String = "HorizontalThumb"
        ''' <summary>
        ''' Property string for VerticalThumb.
        ''' </summary>
        Private Const VerticalThumb As String = "VerticalThumb"
        ''' <summary>
        ''' Internal element for Slider horizontal thumb "HorizontalThumb".
        ''' </summary>
        Private m_horizontalThumb As Thumb
        ''' <summary>
        ''' Internal element for Slider verical thumb "VerticalThumb".
        ''' </summary>        
        Private m_verticalThumb As Thumb
        ''' <summary>
        ''' The slider position at the start of a drag.
        ''' </summary>
        Private m_dragStartValue As Double
        ''' <summary>
        ''' Initializes a new instance of the SensitiveSlider class. You can click anywhere on slider to step to a particular time.
        ''' </summary>
        Public Sub New()
            AddHandler ValueChanged, AddressOf SensitiveSliderValueChanged
        End Sub
        ''' <summary>
        ''' Value changed event (with optional filtering of SliderDrag value changes.
        ''' </summary>
        Public Event FilteredValueChanged As RoutedPropertyChangedEventHandler(Of Double)
        ''' <summary>
        ''' Thumb drag started event. 
        ''' </summary>
        Public Event DragStarted As DragStartedEventHandler
        ''' <summary>
        ''' Thumb drag completed event.
        ''' </summary>
        Public Event DragCompleted As DragCompletedEventHandler
        ''' <summary>
        ''' Gets a value indicating whether the user is currently dragging the thumb.
        ''' </summary>
        <System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)> _
        Public Overridable ReadOnly Property IsDragging() As Boolean
            Get
                If m_horizontalThumb IsNot Nothing AndAlso m_horizontalThumb.IsDragging Then
                    Debug.WriteLine("Horizontal drag!")
                    Return True
                End If

                If m_verticalThumb IsNot Nothing AndAlso m_verticalThumb.IsDragging Then
                    Debug.WriteLine("Vertical drag!")
                    Return True
                End If

                Return False
            End Get
        End Property
        ''' <summary>
        ''' Overridden OnApplyTemplate, sets internal elements and events.
        ''' </summary>
        Public Overrides Sub OnApplyTemplate()
            MyBase.OnApplyTemplate()

            m_horizontalThumb = TryCast(GetTemplateChild(HorizontalThumb), Thumb)
            m_verticalThumb = TryCast(GetTemplateChild(VerticalThumb), Thumb)

            If m_horizontalThumb IsNot Nothing Then
                AddHandler m_horizontalThumb.DragStarted, AddressOf OnDragStarted
                AddHandler m_horizontalThumb.DragCompleted, AddressOf OnDragCompleted
            End If

            If m_verticalThumb IsNot Nothing Then
                AddHandler m_verticalThumb.DragStarted, AddressOf OnDragStarted
                AddHandler m_verticalThumb.DragCompleted, AddressOf OnDragCompleted
            End If

            For Each partName As String In PartNamesArray
                Dim element As FrameworkElement = TryCast(GetTemplateChild(partName), FrameworkElement)
                If element IsNot Nothing Then
                    AddHandler element.MouseLeftButtonDown, AddressOf OnMouseClick
                End If
            Next partName
        End Sub
        ''' <summary>
        ''' Filtered ValueChanged event handler.
        ''' </summary>
        ''' <param name="sender">Source object, Slider.</param>
        ''' <param name="e">Property changed event args.</param>
        Private Sub SensitiveSliderValueChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Double))
            '//Debug.WriteLine("SensitiveSliderValueChanged -- sending change new value:" + e.NewValue.ToString(CultureInfo.CurrentCulture));
            Dim handler As RoutedPropertyChangedEventHandler(Of Double) = FilteredValueChangedEvent
            If handler IsNot Nothing AndAlso (Not IsDragging) Then
                handler(Me, New RoutedPropertyChangedEventArgs(Of Double)(e.OldValue, e.NewValue))
            End If
        End Sub
        ''' <summary>
        ''' Computes the new slider value based on mouse position -- takes into account the orientation of the slider.
        ''' </summary>
        ''' <returns>The new slider value.</returns>
        ''' <param name="args">Mouse button args.</param>
        Protected Function CalcValue(ByVal args As MouseEventArgs) As Double
            Dim pt As Point = args.GetPosition(Me)
            Dim valueNew As Double
            If Me.Orientation = Orientation.Horizontal Then
                valueNew = (((pt.X - (m_horizontalThumb.ActualWidth / 2)) / (ActualWidth - m_horizontalThumb.ActualWidth) * (Maximum - Minimum)) + Minimum)
            Else
                valueNew = (((ActualHeight - pt.Y) - (m_verticalThumb.ActualHeight / 2)) / (ActualHeight - m_verticalThumb.ActualHeight) * ((Maximum - Minimum)) + Minimum)
            End If
            Return valueNew
        End Function
        ''' <summary>
        ''' Handle DragStart event.
        ''' </summary>
        ''' <param name="sender">Source object, Thumb.</param>
        ''' <param name="e">Drag start args.</param>
        Protected Overridable Sub OnDragStarted(ByVal sender As Object, ByVal e As DragStartedEventArgs)
            m_dragStartValue = Me.Value
            RaiseEvent DragStarted(sender, e)
        End Sub
        ''' <summary>
        ''' Handle DragCompleted event.
        ''' </summary>
        ''' <param name="sender">Source object, Thumb.</param>
        ''' <param name="e">Drag completed args.</param>
        Protected Overridable Sub OnDragCompleted(ByVal sender As Object, ByVal e As DragCompletedEventArgs)
            Dim handler As RoutedPropertyChangedEventHandler(Of Double) = FilteredValueChangedEvent
            If handler IsNot Nothing Then
                handler(Me, New RoutedPropertyChangedEventArgs(Of Double)(m_dragStartValue, Me.Value))
            End If

            RaiseEvent DragCompleted(sender, e)
        End Sub
        ''' <summary>
        ''' Send send change event when the mouse clicks down the track bar.
        ''' </summary>
        ''' <param name="sender">Source object, track.</param>
        ''' <param name="args">Mouse button args.</param>
        Protected Overridable Sub OnMouseClick(ByVal sender As Object, ByVal args As MouseButtonEventArgs)
            Value = CalcValue(args)
        End Sub
    End Class
End Namespace
